$input v_fragPos, v_normal, v_texcoord0, v_tangent


#include "../../bgfx/examples/common/common.sh"


SAMPLER2D(s_texColor,  0);
SAMPLER2D(s_texNormal, 1);
SAMPLER2D(s_texAorm, 2);

uniform vec4 u_viewPos;
uniform vec4 u_lightPos;
uniform vec4 u_lightColor;
uniform vec4 u_material; ////x:roughness  y:metallic  z:controlRonghnessMetallic  w: showNormal

#define PI 3.1415926

struct Light {
	vec3 color;
    vec4 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

float DistributionGGX(vec3 N, vec3 H, float roughness)
{
    float a = roughness*roughness;
    float a2 = a*a;
    float NdotH = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;

    float nom   = a2;
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;

    return nom / denom;
}
float GeometrySchlickGGX(float NdotV, float roughness)
{
    float r = (roughness + 1.0);
    float k = (r*r) / 8.0;

    float nom   = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx2 = GeometrySchlickGGX(NdotV, roughness);
    float ggx1 = GeometrySchlickGGX(NdotL, roughness);

    return ggx1 * ggx2;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}

void main()
{
	Light light;
	light.position = mul(u_view, u_lightPos);
	light.color = u_lightColor.xyz;
	light.ambient = vec3(0.03f, 0.03f, 0.03f);
	
	// material parameter
	vec4 texMaterialColor = toLinear(texture2D(s_texColor, vec2(v_texcoord0.x, 1.0f - v_texcoord0.y)));
	vec4 texAorm = texture2D(s_texAorm, vec2(v_texcoord0.x, 1.0f - v_texcoord0.y)); //y:roughness  z:metallic
	vec3 albedo = texMaterialColor.xyz;
	float roughness = u_material.x;
	float metallic = u_material.y;
	float ao = texAorm.x;

	// u_material.z:controlRonghnessMetallic  enum:0(control by slider)  1(control by texture)
	if (u_material.z > 0.5) {
		roughness = texAorm.y;
		metallic = texAorm.z;
	}
	
	// load normal from texture
	vec3 texNormal = texture2D(s_texNormal, vec2(v_texcoord0.x, 1.0f - v_texcoord0.y)).xyz;
	texNormal = normalize(texNormal * 2.0 - 1.0);
	vec3 v_bitangent = normalize(cross(v_normal, v_tangent));
	mat3 TBN = mat3(v_tangent, v_bitangent, v_normal);
	vec3 N = normalize(mul(TBN , texNormal));
	N = mul(u_modelView, vec4(N, 0.0) ).xyz;
	N = normalize(N);

 	vec3 F0 = vec3(0.056, 0.056, 0.056);  //stone's f0
    F0 = mix(F0, albedo, metallic);
	vec3 V = normalize(-v_fragPos);
	vec3 L = normalize(light.position.xyz - v_fragPos) ;
	vec3 H = normalize(V + L);
	vec3 radiance = light.color;

	float NdotL = max(dot(N, L), 0.0);  

	// BRDF-specular
	float D = DistributionGGX(N, H, roughness);   
	float G = GeometrySmith(N, V, L, roughness);      
    vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
	vec3 Ks = F;
	vec3 numerator = D * G * F; 
    float denominator = 4.0 * max(dot(N, V), 0.0) * NdotL + 0.0001; // prevent divide by zero
    vec3 specular = numerator / denominator * radiance * NdotL;  //Ks = F no need to multiply Ks again

	// BRDF-diffuse
	vec3 Kd = vec3(1.0, 1.0, 1.0) - Ks;
	Kd = Kd * (1.0 - metallic);
	vec3 diffuse = Kd * albedo / PI * radiance * NdotL;   

	// ambient
    vec3 ambient = light.ambient * texMaterialColor.xyz * ao;
	
	// Cook-Torrance BRDF + ambient
	vec3 color = diffuse + specular + ambient;
    color = color / (color + vec3(1.0, 1.0, 1.0));    //tonemapping

	gl_FragColor.xyz = color * 10.0; // origin color is too dark
	
	if (u_material.w > 0.5) {
		gl_FragColor.xyz = N;
	}

	gl_FragColor.w = 1.0;
	gl_FragColor = toGamma(gl_FragColor);
}
